package com.yvan.leto.server.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.yvan.Conv;
import com.yvan.YvanUtil;
import com.yvan.leto.SegmentHelper;
import com.yvan.leto.server.dao.RepositoryPersistent;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
public class SpringBootParser implements IParser {

    private static final Pattern EXPRESS_PATTERN = Pattern.compile("(\\$\\{.*?\\})");

    @Override
    @SneakyThrows
    public String process(ParserContext context) {
        //合并所有 Resource
        List<File> resourceList = Lists.newArrayList();
        for (val relativePath : context.getSegment().getConfigFiles()) {
            resourceList.addAll(context.getRepositoryPersistent().repositoryEnvFileList(context.getEnv(), relativePath));
        }
        if (log.isInfoEnabled()) {
            for (val f : resourceList) {
                log.info("springboot load {}", f.getCanonicalPath());
            }
        }
        JsonNode jsonNode = IParser.mergeResourceContentToJsonNode(resourceList);

        //将 Yaml 格式转换为 Properties 格式
        Map<String, Object> properties = Maps.newLinkedHashMap();
        flatMap(properties, "", jsonNode);

        //替换变量
        replaceVariable(properties);
        return YvanUtil.toJsonPretty(properties);
    }

    //替换 yaml 中的变量
    private void replaceVariable(Map<String, Object> properties) {
        for (Map.Entry<String, Object> entry : properties.entrySet()) {
            if (!(entry.getValue() instanceof String)) {
                continue;
            }
            boolean hasChanged = false;
            String value = Conv.NS(entry.getValue());

            if (Strings.isNullOrEmpty(value)) {
                continue;
            }

            Matcher m = EXPRESS_PATTERN.matcher(value);
            StringBuilder sb = new StringBuilder();

            int start = 0;
            while (m.find()) {
                hasChanged = true;
                sb.append(value.substring(start, m.start(1)));

                final String dictKey = m.group(1).substring(2, m.group(1).length() - 1);
                final Object dictValue = properties.get(dictKey);
                if (dictValue == null) {
                    throw new RuntimeException("not found configration:[" + dictKey + "]");
                }
                sb.append(dictValue);

                start = m.end(1);
            }

            if (start < value.length()) {
                sb.append(value.substring(start));
            }
            value = sb.toString();

            if (hasChanged) {
                entry.setValue(value);
            }
        }
    }

    private void flatMap(Map<String, Object> map, String prefixField, JsonNode parent) {
        if (parent == null) {
            return;
        }
        String prefix = Strings.isNullOrEmpty(prefixField) ? prefixField : prefixField + ".";

        Iterator<String> fieldNames = parent.fieldNames();
        while (fieldNames.hasNext()) {
            String fieldName = fieldNames.next();
            JsonNode jn = parent.get(fieldName);

            if (jn.isObject()) {
                flatMap(map, prefix + fieldName, jn);

            } else if (jn.isArray()) {
                ArrayNode arrayNode = (ArrayNode) jn;
                int index = 0;
                for (JsonNode element : arrayNode) {
                    if (element.isObject()) {
                        flatMap(map, prefix + fieldName + "[" + index + "]", element);

                    } else {
                        map.put(prefix + fieldName + "[" + index + "]", getJsonNodeValue(element));
                    }
                    index++;
                }

            } else {
                map.put(prefix + fieldName, getJsonNodeValue(jn));
            }
        }
    }

    private Object getJsonNodeValue(JsonNode jn) {
        if (jn.isNull()) {
            return "";

        } else if (jn.isBoolean()) {
            return jn.asBoolean();

        } else if (jn.isDouble() || jn.isFloat()) {
            return jn.asDouble();

        } else if (jn.isInt() || jn.isShort()) {
            return jn.asInt();

        } else if (jn.isLong()) {
            return jn.asLong();

        } else if (jn.isTextual()) {
            return jn.asText();

        }
        throw new RuntimeException("unkown nodetype:" + jn);
    }


    /*
    public static void main(String[] args) {
        String line = "${ui_template.value}";
        Map<String, String> properties = Maps.newLinkedHashMap();
        properties.put("ui_template.value", "/home/www");
        properties.put("v1", "v");

        Matcher m = EXPRESS_PATTERN.matcher(line);
        StringBuilder sb = new StringBuilder();

        int start = 0;
        while (m.find()) {
            sb.append(line.substring(start, m.start(1)));

            final String dictKey = m.group(1).substring(2, m.group(1).length() - 1);
            sb.append(properties.get(dictKey));

            start = m.end(1);
        }

        if (start < line.length()) {
            sb.append(line.substring(start));
        }
        System.out.println(sb.toString());
    }
    */
}
